import Cesium from '../Ces/Cesium'
import LayerManager from '../Layer/LayerManager'
import WeDisplay from './WeDisplay'
import WeGridMovableCube from './WeGridMovableCube'
import WeGridMovableFace from './WeGridMovableFace'
import WeSurface from './WeSurface'
import WeDataProvider from './WeDataProvider'
import WeGridMovablePolyline from './WeGridMovablePolyline'
import { WeGridMovableOptions, WeGridMovableStyle } from './WeGridMovableStyle'

class WeGridMovable {
  show: boolean = true
  private repeatFactor: number
  private startLod: number
  private endLod: number
  private currentLod: number = 0
  private _showSymbol: boolean = false
  private display: WeDisplay
  private dataProvider: WeDataProvider
  private _layerManager: LayerManager
  private windLastChangeFrameNumber: number = 0
  private primitiveSymbol: WeSurface
  public primitiveFullExtent: WeGridMovableCube | WeGridMovableFace | WeGridMovablePolyline
  public primitiveLocalExtent: WeGridMovableCube | WeGridMovableFace | WeGridMovablePolyline
  constructor(options: WeGridMovableOptions, display, dataProvider, layerManager: LayerManager) {
    this._layerManager = layerManager
    this.display = display
    this.dataProvider = dataProvider
    this.repeatFactor = options.iconOptions?.repeatFactor ?? 16
    this.startLod = options.iconOptions?.startLod ?? 0
    this.endLod = options.iconOptions?.endLod ?? 12

    const buildPolylineVolume = options.particleStyle === WeGridMovableStyle.PolylineVolume

    const createPrimitive = (options) => {
      return buildPolylineVolume
          ? new WeGridMovableCube(options, display)
          : new WeGridMovablePolyline(options, display)
    }

    this.primitiveFullExtent = createPrimitive(options)

    const localViewOptions = options.localViewOptions
    if (localViewOptions) {
      const scaler = localViewOptions.scaler ?? 0
      if (scaler > 0) {
        const localOptions = {
          ...options,
          // colorize: false,
          numLon: Math.floor(options.numLon * scaler),
          numLat: Math.floor(options.numLat * scaler),
        }
        this.primitiveLocalExtent = createPrimitive(localOptions)
      }
    }
  }

  set showArrow(value) {
    this.primitiveFullExtent.showArrow = value
    if (this.primitiveLocalExtent) this.primitiveLocalExtent.showArrow = value
  }

  set showSymbol(value) {
    this._showSymbol = value
    this._layerManager.context.enableWindTexture()
  }

  get showSymbol() {
    return this._showSymbol
  }

  set freezing(value) {
    this.primitiveFullExtent.freezing = value
    if (this.primitiveLocalExtent) this.primitiveLocalExtent.freezing = value
  }

  set colorize(value) {
    this.primitiveFullExtent.weUniform.Properties.colorize = value ? 1.0 : 0.0
    if (this.primitiveLocalExtent)
      this.primitiveLocalExtent.weUniform.Properties.colorize = value ? 1.0 : 0.0
  }

  get colorize() {
    return this.primitiveFullExtent.weUniform.Properties.colorize === 1.0
  }

  update(frameState) {
    if (!frameState.passes.render || (!this.show && !this.showSymbol)) return

    const scaleListener = frameState.scaleListener
    if (this.currentLod !== scaleListener.currentLod) {
      let dynamicSpeedFactor = 1
      let repeatFactor = this.repeatFactor

      const currentLod = scaleListener.currentLod
      const startLod = this.startLod
      const endLod = this.endLod
      if (currentLod < startLod) {
        let n = startLod - currentLod
        let m = 1
        if (currentLod < endLod) {
          n = startLod - endLod
          m = endLod - currentLod
        }
        repeatFactor *= Math.pow(0.5, n)
        dynamicSpeedFactor = Cesium.Math.clamp(1 / n / m, 0.01, 1.0)
      }

      if (this.primitiveFullExtent) {
        this.primitiveFullExtent.weUniform.Properties.dynamicSpeedFactor = dynamicSpeedFactor
      }
      if (this.primitiveLocalExtent) {
        this.primitiveLocalExtent.weUniform.Properties.dynamicSpeedFactor = dynamicSpeedFactor
      }

      this.display.iconEffect.repeatFactor = Cesium.Math.clamp(repeatFactor, 1, repeatFactor)
      this.currentLod = currentLod
    }

    if (this.showSymbol && frameState.context.weContext.windSymbolTexture) {
      if (!this.primitiveSymbol) {
        this.primitiveSymbol = new WeSurface({
          display: this.display,
          dataProvider: this.dataProvider,
          clampToGround: true,
          useIconEffect: true,
        })
      }
      this.primitiveSymbol.update(frameState)
    }

    if (this.show) {
      this.primitiveFullExtent?.update(frameState)

      if (this.primitiveLocalExtent) {
        const viewExtentEvent = this._layerManager.viewExtentEvent
        if (viewExtentEvent.lastChangeFrameNumber !== this.windLastChangeFrameNumber) {
          this.windLastChangeFrameNumber = viewExtentEvent.lastChangeFrameNumber
          const viewExtent = Cesium.Rectangle.intersection(
            this.display.imageryLayer.rectangle,
            viewExtentEvent.viewExtent,
          )
          if (viewExtent) {
            this.primitiveLocalExtent.viewExtent = viewExtent
          }
        }
        this.primitiveLocalExtent.update(frameState)
      }
    }
  }

  destroy() {
    this.primitiveFullExtent?.destroy()
    this.primitiveLocalExtent?.destroy()
    this.primitiveSymbol?.destroy()
    return Cesium.destroyObject(this)
  }

  isDestroyed() {
    return false
  }
}

export default WeGridMovable
